#pragma once
namespace graph
{
   namespace details
   {
      struct graph_inf_t
      {
         graph_inf_t(graph_id_t id, lat_lon_t min_lat, lat_lon_t min_lon,
                     lat_lon_t max_lat, lat_lon_t max_lon, graph_int_t vertex_count,
                     graph_int_t edge_count)
            :  id_(id)
            ,  min_lat_(min_lat)
            ,  min_lon_(min_lon)
            ,  max_lat_(max_lat)
            ,  max_lon_(max_lon)
            ,  vertex_count_(vertex_count)
            ,  edge_count_(edge_count)
         {}
         graph_inf_t()
         {}
         graph_id_t id_;
         lat_lon_t min_lat_;
         lat_lon_t min_lon_;
         lat_lon_t max_lat_;
         lat_lon_t max_lon_;
         graph_int_t vertex_count_;
         graph_int_t edge_count_;
      };
   
      struct graph_base_t
      {
         graph_base_t(graph_id_t graph_id, 
                      size_t vertex_count, size_t edge_count, 
                      lat_lon_t min_lat, lat_lon_t min_lon, 
                      lat_lon_t max_lat, lat_lon_t max_lon)
            :  inf_(graph_id, min_lat, min_lon, max_lat, max_lon, vertex_count, edge_count)
         {}
         graph_base_t(details::graph_inf_t inf)
            :  inf_(inf)
         {}
         graph_id_t get_graph_id() const;
         size_t get_edge_count() const;
         size_t get_vertex_count() const;
         lat_lon_t get_min_lat() const;
         lat_lon_t get_min_lon() const;
         lat_lon_t get_max_lat() const;
         lat_lon_t get_max_lon() const;
      protected:
         details::graph_inf_t inf_;
      };
      
      typedef boost::shared_ptr<boost::interprocess::file_mapping> mapped_file_ptr_t;
      typedef boost::shared_ptr<boost::interprocess::mapped_region> mapped_region_ptr_t;
      struct graph_finalizer_t
      {
         graph_finalizer_t(graph_base_t* graph, 
                           mapped_file_ptr_t m_file, 
                           mapped_region_ptr_t region)
            :  graph_(graph)
            ,  m_file_(m_file)
            ,  region_(region)
         {}
      private:
         graph_base_t* graph_;
         mapped_file_ptr_t m_file_;
         mapped_region_ptr_t region_;
      };
      typedef std::auto_ptr<graph_finalizer_t> graph_finalizer_ptr_t;
      
      #pragma pack(1)
      struct graph_sequential_t: graph_base_t
      {
         graph_sequential_t(details::graph_inf_t inf)
            :  details::graph_base_t(inf) 
         {}
         
         vertex_t const & operator [] (size_t idx) const;
         vertex_t & operator [] (size_t idx);
         vertex_t const & get_vertex_by_id(size_t idx) const;
         vertex_t & get_vertex_by_id(size_t idx);
         std::pair<details::edge_real_t*, details::edge_real_t*> get_vertex_edges(vertex_in_graph_id_t idx) const;
         std::pair<details::edge_real_t*, details::edge_real_t*> get_vertex_in_edges(vertex_in_graph_id_t idx) const;
         static void load_from_file(std::string file_name, graph_sequential_t** result, details::graph_finalizer_ptr_t& finalizer);
      private:
         details::edge_real_t* begin_of_edges_; 
         details::edge_real_t* begin_of_in_edges_;
         char data_[];
         friend struct details::graph_mutable_t;
      };

      #pragma pack(1)
      struct graph_not_sequential_t: graph_base_t
      {
         //assuming that vertices and edges allocated with malloc
         //but when using mapped file - no need to free them
         graph_not_sequential_t(details::graph_inf_t inf,
                                vertex_t* vertices, details::edge_real_t* edges)
            :  details::graph_base_t(inf) 
            ,  vertices_(vertices)
            ,  edges_(edges)
         {}
         
         vertex_t const & operator [] (size_t idx) const;
         vertex_t& operator [] (size_t idx);
         vertex_t const & get_vertex_by_id(size_t idx) const;
         vertex_t & get_vertex_by_id(size_t idx);
         std::pair<details::edge_real_t*, details::edge_real_t*> get_vertex_edges(vertex_in_graph_id_t idx) const;
      private:
         vertex_t* vertices_;
         details::edge_real_t* edges_;
         static void load_from_file(std::string file_name, graph_not_sequential_t** result, details::graph_finalizer_ptr_t& finalizer);
         friend struct details::graph_mutable_t;
         friend struct global_data_t;
      };
      typedef graph_sequential_t graph_storage_model_t;
   }
   
}